package com.zy.swagger.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zy.swagger.constant.ProjectConstant;
import com.zy.swagger.entity.sys.SysMenu;
import com.zy.swagger.entity.sys.SysUser;
import com.zy.swagger.exception.BaseException;
import com.zy.swagger.service.sys.SysMenuService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;


/**
 * @author ZY
 */
public class LoginFilter extends UsernamePasswordAuthenticationFilter {

    @Value("${spring.profiles.active}")
    private String env;

    @Resource
    private SessionRegistry sessionRegistry;

    @Resource
    private SysMenuService sysMenuService;

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        response.setCharacterEncoding("UTF-8");
        String postMethod = "POST";
        if (!request.getMethod().equalsIgnoreCase(postMethod)) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + request.getMethod());
        }
        String verifyCode = (String) request.getSession().getAttribute(ProjectConstant.SESSION_CODE_KEY);
        if (request.getContentType().contains(MediaType.APPLICATION_JSON_VALUE) || request.getContentType().contains(MediaType.APPLICATION_JSON_UTF8_VALUE)) {
            Map<String, String> loginData = new HashMap<>(4);
            try {
                // 拿到前端登录请求中传递的验证码code
                loginData = new ObjectMapper().readValue(request.getInputStream(), Map.class);
                String code = loginData.get("code");
                // 生产环境才校验验证码
                if (Objects.equals(env, "prod")) {
                    checkCode(code, verifyCode);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            String username = loginData.get(getUsernameParameter());
            String password = loginData.get(getPasswordParameter());
            if (username == null) {
                username = "";
            }
            if (password == null) {
                password = "";
            }
            username = username.trim();
            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
            setDetails(request, authRequest);
            SysUser principal = new SysUser();
            principal.setUsername(username);
            sessionRegistry.registerNewSession(request.getSession(true).getId(), principal);
            Authentication authenticate = this.getAuthenticationManager().authenticate(authRequest);
            if (authenticate.isAuthenticated()) {
                SysUser currentUser = (SysUser) authenticate.getPrincipal();
                // 如果登录成功，则查询用户菜单返回
                List<SysMenu> menus = sysMenuService.getMenusByUserId(currentUser.getId());
                currentUser.setMenus(menus);
                return authenticate;
            }
            throw new BaseException(400, "用户名或密码错误");
        } else {
            // 生产环境才校验验证码
            if (Objects.equals(env, "prod")) {
                checkCode(request.getParameter("code"), verifyCode);
            }
            return super.attemptAuthentication(request, response);
        }
    }

    public void checkCode(String code, String verifyCode) {
        if (code == null || verifyCode == null || "".equals(code) || !verifyCode.equalsIgnoreCase(code)) {
            //验证码不正确
            throw new AuthenticationServiceException("验证码不正确");
        }
    }
}
